import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.StyledDocument;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;


/**
 * Title:  Tree.java
 * Description:  implements undo and redo actions
 * Copyright:    Copyright (c) 2010
 * @author WANG Jiechao and the Java Tutorial
 * @version 1.0
 */

public class UndoAndRedo{
	JTextPane textPane;
	AbstractDocument doc;
    protected UndoAction undoAction = new UndoAction();
    protected RedoAction redoAction = new RedoAction();
    protected UndoManager undo = new UndoManager();
    static JFrame frame;
    static JMenuItem undoItem;
    static JMenuItem redoItem;
    

    
    public void setTextPane (JTextPane textPane){
    	this.textPane = textPane;
    	StyledDocument styledDoc = textPane.getStyledDocument();
        if (styledDoc instanceof AbstractDocument) {
            doc = (AbstractDocument)styledDoc;
            //doc.setDocumentFilter(new DocumentSizeFilter(MAX_CHARACTERS));
        } else {
            System.err.println("Text pane's document isn't an AbstractDocument!");
            System.exit(-1);
        }
        doc.addUndoableEditListener(new MyUndoableEditListener());
    }
    
    
    protected class MyUndoableEditListener implements UndoableEditListener {
    	public void undoableEditHappened(UndoableEditEvent e) {
    		//Remember the edit and update the menus.
    		undo.addEdit(e.getEdit());
    		undoAction.updateUndoState();//????????????????
    		redoAction.updateRedoState();
    	}
    }
    
    
    class UndoAction extends AbstractAction {
        /**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public UndoAction() {
            super("Undo");
            setEnabled(false);
        }

        public void actionPerformed(ActionEvent e) {
        	if (undo.canUndo()){ 
        		undo.undo();
        	    updateUndoState();
                redoAction.updateRedoState();
                System.out.println("it is undoing");
        	}
        	else{
        		JOptionPane.showMessageDialog(frame,
            			"The text has not been changed so that you cannot undo it ",
            			"ERROR",
                	    JOptionPane.ERROR_MESSAGE);
        	}
        }

        protected void updateUndoState() {
            if (undo.canUndo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getUndoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Undo");
            }
        }
    }

    class RedoAction extends AbstractAction {
        /**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public RedoAction() {
            super("Redo");
            setEnabled(false);
        }

        public void actionPerformed(ActionEvent e) {
        	if (undo.canRedo()){ 
        		undo.redo();
        	    updateRedoState();
                undoAction.updateUndoState();
        	}
        	else{
        		JOptionPane.showMessageDialog(frame,
            			"The text has not been changed so that you cannot redo it ",
            			"ERROR",
                	    JOptionPane.ERROR_MESSAGE);
        	}
        }

        protected void updateRedoState() {
            if (undo.canRedo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getRedoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Redo");
            }
        }
    }
    
	public void myAction(ActionEvent e, int i) {
		if (i==1){
			//UndoAction undoAction = new UndoAction();
			undoAction.actionPerformed(e);
		}
		if (i==2){
			//RedoAction redoAction = new RedoAction();
			redoAction.actionPerformed(e);
		}
	}
	
    public static void main(String[] args) {
    	frame = new JFrame();
    	frame.setDefaultCloseOperation(3);
    	frame.setSize(800,600);
    	frame.setLayout(new BorderLayout());
    	JMenuBar menuBar = new JMenuBar(); 
    	JMenu file = new JMenu("File");
    	undoItem = new JMenuItem("Undo");
    	redoItem = new JMenuItem("Redo");
    	file.add(undoItem);
    	file.add(redoItem);
    	menuBar.add(file);
    	
    	frame.setJMenuBar(menuBar);
    	JTextPane textPane = new JTextPane();  	
    	//textPane.add(textArea);
    	textPane.setText("This frame is only for testing");
    	frame.getContentPane().add(textPane,BorderLayout.CENTER);    
    	UndoAndRedo undoAndRedo = new UndoAndRedo();
    	undoAndRedo.setTextPane(textPane);
    	//undoItem.addActionListener(undoAndRedo); 
    	//redoItem.addActionListener(undoAndRedo); 
    	
    	frame.setVisible(true);
    	
    }
}
